/*
 * Copyright (c) 2018, apexes.net. All rights reserved.
 *
 *         http://www.apexes.net
 *
 */
package net.apexes.commons.ormlite;

import com.j256.ormlite.field.DatabaseFieldConfig;
import com.j256.ormlite.table.DatabaseTableConfig;
import com.j256.ormlite.table.ObjectFactory;
import net.apexes.commons.lang.Reflect;
import net.apexes.commons.lang.Strings;

import java.lang.reflect.Constructor;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author <a href="mailto:hedyn@foxmail.com">HeDYn</a>
 *
 * @param <T>
 */
public abstract class Table<T> {

    private final DatabaseTableConfig<T> config;
    
    private final boolean upperCaseName;

    private final List<Column> columns;

    private final ObjectFactory<T> objectFactory;
    
    protected Table(Class<T> dataClass) {
        this(dataClass, false);
    }
    
    protected Table(Class<T> dataClass, boolean upperCaseName) {
        this(dataClass, false, null);
    }
    
    protected Table(Class<T> dataClass, String tableName) {
        this(dataClass, false, tableName);
    }
    
    protected Table(Class<T> dataClass, boolean upperCaseName, String tableName) {
        this.upperCaseName = upperCaseName;
        if (tableName == null) {
            tableName = convertToDatabaseName(Strings.uncapitalize(dataClass.getSimpleName()));
        }
        this.config = new UnreflectDatabaseTableConfig<>(this, dataClass, tableName, new ArrayList<DatabaseFieldConfig>());
        this.columns = new ArrayList<>();
        this.objectFactory = new ObjectFactory<T>() {
            @Override
            public Object createObject(Constructor construcor, Class dataClass) throws SQLException {
                return newInstance();
            }
        };
    }

    protected ColumnFactory getColumnFactory() {
        return null;
    }
    
    protected ColumnBuilder<T> field(String fieldName) {
        return new ColumnBuilder<>(this, fieldName, getColumnFactory());
    }

    public Class<T> dataClass() {
        return config.getDataClass();
    }
    
    public String name() {
        return config.getTableName();
    }

    public DatabaseTableConfig<T> config() {
        return config;
    }

    ObjectFactory<T> objectFactory() {
        return objectFactory;
    }

    void addColumn(Column column) {
        config.getFieldConfigs().add(column.config());
        columns.add(column);
    }
    
    String convertToDatabaseName(String name) {
        return underscoreName(name, upperCaseName);
    }

    public T newInstance() {
        return Reflect.on(dataClass()).get();
    }

    public Object getFieldValue(T instane, String fieldName) {
        return Reflect.on(instane).get(fieldName);
    }

    public void setupFieldValue(T instane, String fieldName, Object value) {
        Reflect.on(instane).set(fieldName, value);
    }

    private static String underscoreName(String name, boolean upperCase) {
        if (upperCase) {
            return Strings.underscore(name).toUpperCase();
        }
        return Strings.underscore(name);
    }

    protected static ForeignKey foreignKey(Column column, String referenceTable, String referenceColumn) {
        return new ForeignKeyImpl(column, referenceTable, referenceColumn);
    }

    protected static IndexBuilder index(String indexName) {
        return new IndexBuilder(indexName);
    }

}
